package org.nimi317.web_gis.utils;

import cn.hutool.core.io.IoUtil;
import lombok.SneakyThrows;
import org.nimi317.web_gis.exception.E;
import org.nimi317.web_gis.exception.RException;
import org.nimi317.web_gis.form.post.ModelPost;
import org.nimi317.web_gis.runnable.ModelRunnable;
import org.nimi317.web_gis.service.ModelService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author thunderobot
 */
@Component
public class ModelUtils {

    private final ModelService modelService;

    private final static String basePath = "C:\\Users\\thunderobot\\Desktop\\毕业设计\\web_gis\\src\\main\\resources\\data";


    private final BlockingQueue<Runnable> trainingQueue;

    private final ModelRunnable modelRunnable;


    public ModelUtils(ModelService modelService, @Value("${model.maxWaitingSize}") Integer maxWaitingSize,
                      @Value("${model.numThreads}") Integer numThreads, @Lazy ModelRunnable modelRunnable) {
        this.modelService = modelService;
        // 创建一个具有最大等待队列大小的BlockingQueue
        this.trainingQueue = new ArrayBlockingQueue<>(maxWaitingSize == null ? 5 : maxWaitingSize);
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(numThreads == null ? 1 : numThreads);
        this.modelRunnable = modelRunnable;

        // 提交一个任务到线程池，它不断从BlockingQueue中获取任务并执行
        executorService.submit(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 从队列中获取任务，如果队列为空则阻塞
                    Runnable task = trainingQueue.take();
                    // 执行任务
                    task.run();
                } catch (InterruptedException e) {
                    // 线程被中断，退出循环
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
    }

    // 提交一个训练任务
    public boolean submitTrainingTask(Runnable trainingTask) {
        // 尝试将任务放入队列，如果队列已满则返回false
        return trainingQueue.offer(trainingTask);
    }

    /**
     * 保存csv文件
     */
    public String saveCsv(MultipartFile file) {
        String s = file.getOriginalFilename().split("\\.")[1];
        if (!"csv".equals(s)) {
            throw new RException(E.FileException);
        }
        String fileName = UUID.randomUUID() + ".csv";
        String out = basePath + "/" + fileName;
        save(file, out);
        return out;
    }

    @SneakyThrows
    public void save(MultipartFile file, String out) {
        File newFile = new File(out);
        //检查如果路径文件夹不存在则创建
        File parentFile = newFile.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        FileOutputStream stream = new FileOutputStream(newFile);
        stream.write(file.getBytes());
        IoUtil.close(stream);
    }

    public boolean train(Integer id, String url, ModelPost post) {
        return this.submitTrainingTask(() -> {
            try{
                modelRunnable.run(id, url, post);
            }catch (Exception e) {
                modelService.handleError(id);
            }
        });
    }
}
